<?php
// +----------------------------------------------------------------------
// | View 视图服务
// +----------------------------------------------------------------------
// | * 视图层
// | * 1.查询所有关联表的字段
// | * 2.处理字段（可显示、可编辑、可排序、可分组、可过滤）、还要通过临时字段、字段权限进行判断，组装出view需要的字段
// | * 3.组装view视图的表格列
// +----------------------------------------------------------------------
// | 错误编码头 231xxx
// +----------------------------------------------------------------------

namespace common\service;

use common\exception\LogicException;
use common\model\EntityModel;
use common\model\PlanModel;
use common\model\ProjectModel;
use common\model\ReviewRequestModel;
use common\model\StatusModel;
use common\model\StepCategoryModel;
use common\model\StepModel;
use common\model\TaskMemberModel;
use common\model\TaskModel;
use common\model\TimelogModel;
use common\model\UserModel;
use common\model\WorkTimeRecordModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use think\module\Module;

class WorkTimeRecordService
{
    use SingletonTrait;

    /**
     * 获取工时记录
     * @param $tenantId
     * @param $userId
     * @param $date
     * @param $projectId
     * @param $unionId
     * @param $taskFilter
     * @return array|array[]
     */
    public function getWorkTimeRecord($tenantId, $userId, $date, $projectId, $unionId, $taskFilter)
    {
        // 获取当前天数
        $time = strtotime(date('Y-m-d', strtotime($date)));
        $nextTime = strtotime("+1 day", $time);
        $todayFinalDelivery = $taskFilter['today_final_delivery'] ?? false;
        unset($taskFilter['today_final_delivery']);

        // 查询今日计划交付
        $planDoneEpisodeStepCategoryList = model(PlanModel::class)
            ->join("task_relation_tag s_tag on s_tag.task_id = plan.task_id and s_tag.link_module_code in ('step_category','show_step_category')")
            ->join("task_relation_tag e_tag on e_tag.task_id = plan.task_id and e_tag.link_module_code = 'episode'")
            ->where(['plan.scope' => PlanModel::SCOPE_SINGLE, 'plan.type' => PlanModel::TYPE_STEP_CATEGORY])
            ->where(['plan.end_time' => ['BETWEEN', [$time, $nextTime - 1]]])
            ->field('e_tag.link_id as episode_id,s_tag.link_id as step_category_id')
            ->select();
        // 今日计划完成
        $tmpDeliveryWhereFilter = "(task.plan_end_time >= $time and task.plan_end_time < $nextTime and task_member.partner = $userId)";
        if (!empty($planDoneEpisodeStepCategoryList)) {
            $episodeCategoryKey = [];
            foreach ($planDoneEpisodeStepCategoryList as $item) {
                $episodeCategoryKey[] = "'" . $item['episode_id'] . '-' . $item['step_category_id'] . "'";
            }
            $episodeCategoryKey = join(',', $episodeCategoryKey);
            $tmpDeliveryWhereFilter .= " or (CONCAT(task.episode_id,'-',task.step_category_id) IN ($episodeCategoryKey) and task_member.partner = $userId)";
        }
        $tmpDeliveryWhereFilter = trim($tmpDeliveryWhereFilter, 'or ');

        $closedTaskStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();
        $deliveryTaskList = model(TaskModel::class)
            ->join('entity on task.entity_id = entity.id', 'LEFT')
            ->join('task_member on task_member.task_id = task.id')
            ->where($tmpDeliveryWhereFilter)
            ->where($taskFilter)
            ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $closedTaskStatus['id']]])
            ->field('task.id,task.created_by,task.tenant_id,task.entity_module_id,task.step_type')->select();

        // 仅显示今日必须完成和今日交付的任务
        if ($todayFinalDelivery) {
            if (empty($deliveryTaskList)) {
                return [];
            }
            $deliveryTaskIds = array_column($deliveryTaskList, 'id');
            $taskFilter[] = ['task.id' => ['IN', $deliveryTaskIds]];
        }

        // 部门统计
        if (!empty($departmentId)) {
            $departmentUserList = DepartmentReportService::getInstance()->getDepartmentUserList($departmentId);
            if (empty($departmentUserList)) { // 没有查到当前部门下的用户
                return [];
            }
            $userId = ['IN', array_column($departmentUserList, 'saas_user_id')];
        }

        $workTimeRecordFilter = [
            'work_time_record.tenant_id' => $tenantId,
            'work_time_record.user_id' => $userId,
            '_string' => "work_time_record.record_time >= {$time} and work_time_record.record_time < {$nextTime}"
        ];

        $taskModuleId = module_by_code('task')['id'];
        if (!empty($projectId)) {
            $workTimeRecordFilter['work_time_record.project_id'] = $projectId;
            //判定work_time是否为空, 查询timeLog
            $timeLogInProjectWhere = [
                'timelog.tenant_id' => $tenantId,
                'timelog.created_by' => $userId,
                'task.project_id' => $projectId,
                '_string' => "timelog.start_time >= {$time} and timelog.start_time < {$nextTime}"
            ];
        } else {
            //判定work_time是否为空, 查询timeLog
            $timeLogInProjectWhere = [
                'timelog.tenant_id' => $tenantId,
                'timelog.created_by' => $userId,
                "timelog.module_id" => $taskModuleId,
                '_string' => "timelog.start_time >= {$time} and timelog.start_time < {$nextTime}"
            ];
        }

        $timeLog = model(TimelogModel::class)
            ->join("task on timelog.link_id = task.id and timelog.module_id = {$taskModuleId}")
            ->join('entity on task.entity_id = entity.id', 'LEFT')
            ->where($timeLogInProjectWhere)
            ->where($taskFilter)
            ->field("task.step_type,timelog.tenant_id,timelog.link_id,timelog.module_id,timelog.created_by,timelog.start_time,timelog.end_time,timelog.complete")
            ->order('timelog.id desc')
            ->select();

        // 查询工作记录
        if (!empty($taskFilter)) { // 如果有任务筛选条件
            $workTimeRecordList = model(WorkTimeRecordModel::class)
                ->join('task on work_time_record.link_id = task.id', 'LEFT')
                ->join('entity on task.entity_id = entity.id', 'LEFT')
                ->where($workTimeRecordFilter)
                ->where($taskFilter)
                ->field('work_time_record.id,work_time_record.tenant_id,work_time_record.link_id,work_time_record.module_id,work_time_record.type,work_time_record.project_id,work_time_record.work_time,work_time_record.user_id,work_time_record.record_time,work_time_record.type')
                ->order('work_time_record.id desc')
                ->select();
        } else {
            $workTimeRecordList = model(WorkTimeRecordModel::class)
                ->where($workTimeRecordFilter)
                ->field('id,tenant_id,link_id,module_id,type,project_id,work_time,user_id,record_time,type')
                ->order('id desc')
                ->select();
        }


        //如果不是当前用户
        if (empty($unionId)) {
            $unionId = model(UserModel::class)->field("id,union_id")->find($userId);
            if (empty($unionId)) {
                return [];
            } else {
                $unionId = $unionId['union_id'];
            }
        }


        $workHourList = teamones_request('teamones-work-hour', 'dingtalk/get_user_work_times', [
            "user_id_list" => [$unionId],
            "tenant_id" => $tenantId,
            "work_date_from" => date('Y-m-d H:i:s', $time),
            "work_date_to" => date('Y-m-d H:i:s', $nextTime)
        ]);
        $workHour = $workHourList["data"][0]["work_every_day_min"][$time] ?? [];

        if (!empty($workHour)) {
            //不为空证明打了卡, 查询出未记录的
            $workTimeRecordTaskIds = [];
            foreach ($workTimeRecordList as $workTimeRecordItem) {
                if ($workTimeRecordItem['module_id'] === module_by_code('task')['id']) {
                    $workTimeRecordTaskIds[$workTimeRecordItem['link_id']] = $workTimeRecordItem['link_id'];
                }

            }
            $workTimeRecordTaskIds = array_values($workTimeRecordTaskIds);
            foreach ($timeLog as $index => $timeLogItem) {
                //排除掉重复,已经生成的将不在记录
                if (in_array($timeLogItem['link_id'], $workTimeRecordTaskIds)) {
                    unset($timeLog[$index]);
                    continue;
                }
                // 添加工作时间
                if ($timeLogItem["complete"] == 'no') {
                    $timeLogItem['work_time'] = null;
                } else {
                    $timeLogItem['work_time'] = 0;
                }
                $timeLog[$index] = $timeLogItem;
            }
        } else {
            // 找出指定天内的time_log
            $timeLog = array_map(function ($timeLogItem) use ($nextTime) {
                // 添加工作时间
                if ($timeLogItem["complete"] == 'no') {
                    $timeLogItem['work_time'] = null;
                } else {
                    $timeLogItem['work_time'] = $timeLogItem['end_time'] - $timeLogItem['start_time'];
                }
                return $timeLogItem;
            }, $timeLog);
        }


        //合并任务总计 (未得出时间的不在展示)
        $timeLogResult = [];
        foreach ($timeLog as $timeLogItem) {
            if (!isset($timeLogResult[$timeLogItem['link_id']])) {
                $timeLogResult[$timeLogItem['link_id']] = $timeLogItem;
            } else {
                //工时累计
                if (!empty($timeLogResult[$timeLogItem['link_id']]['work_time']) && !empty($timeLogItem['work_time'])) {
                    $timeLogResult[$timeLogItem['link_id']]['work_time'] = $timeLogResult[$timeLogItem['link_id']]['work_time'] + $timeLogItem['work_time'];
                }
            }
        }

        //追加到 work_time 中
        foreach ($timeLogResult as $timeLogResultItem) {
            $workTimeRecordList[] = [
                'tenant_id' => $timeLogResultItem['tenant_id'],
                'link_id' => $timeLogResultItem['link_id'],
                'module_id' => $timeLogResultItem['module_id'],
                'type' => WorkTimeRecordModel::TYPE_TO_DO,
                'work_time' => $timeLogResultItem['work_time'],
                'user_id' => $timeLogResultItem['created_by'],
                'record_time' => strtotime(date('Y-m-d', $timeLogResultItem['start_time']))
            ];
        }

        // 追加今日必须完成和交付任务到 work_time 中
        foreach ($deliveryTaskList as $deliveryTaskItem) {
            //排除掉重复,已经生成的将不在记录
            if (in_array($deliveryTaskItem['id'], array_column($workTimeRecordList, 'link_id'))) {
                continue;
            }
            $workTimeType = WorkTimeRecordModel::TYPE_STANDARD_TASK; // 默认标准修正任务类型
            $workTimeRecordList[] = [
                'tenant_id' => $deliveryTaskItem['tenant_id'],
                'link_id' => $deliveryTaskItem['id'],
                'module_id' => module_by_code('task')['id'],
                'type' => $workTimeType,
                'work_time' => 0,
                'user_id' => $userId,
                'record_time' => $time,
                'is_today_delivery_final' => true
            ];
        }

        $taskWorkTimeRecordList = [];
        foreach ($workTimeRecordList as $workTimeRecordItem) {
            if ($workTimeRecordItem['module_id'] === module_by_code('task')['id']) {
                if (!in_array($workTimeRecordItem['link_id'], $taskWorkTimeRecordList)) {
                    $taskWorkTimeRecordList[] = $workTimeRecordItem['link_id'];
                }
            }
        }

        $taskFields = [
            'task.id',
            'task.name',
            'task.project_id',
            'task.json',
            'task.plan_end_time',
            'task.episode_id',
            'task.step_category_id',
            'task.entity_module_id',
            'task.step_type',
            'entity.id',
            'entity.name',
            'entity.initial_episode_code',
            'entity.showings_number',
            'project.id',
            'project.name',
            'step.name',
            'step_category.name'
        ];

        $entityMap = [];
        if (!empty($taskWorkTimeRecordList)) {
            $entityList = model(TaskModel::class)
                ->join("entity on entity.id = task.entity_id", 'LEFT')
                ->join('project on project.id = entity.project_id', 'LEFT')
                ->join('step on task.step_id = step.id', 'LEFT')
                ->join('step_category on task.step_category_id = step_category.id', 'LEFT')
                ->where(['task.id' => ['IN', $taskWorkTimeRecordList]])
                ->where($taskFilter)
                ->field(build_complex_query_fields($taskFields, '__'))
                ->group('task.id')
                ->order('task.id desc')
                ->select();
            if (empty($entityList)) {
                return [];
            }
            $stepEpisodeIds = [];
            $todoTaskIds = [];
            $stepCategoryIds = [];

            foreach ($entityList as $entityItem) {

                $entityItem = separate_complex_query_data($entityItem, '__');
                if ($entityItem['task']['step_type'] == TaskModel::STEP_TYPE_STEP) {
                    $stepEpisodeIds[] = $entityItem['task']['episode_id'];
                    $stepCategoryIds[] = $entityItem['task']['step_category_id'];
                } else {
                    $todoTaskIds[] = $entityItem['task']['id'];
                }
            }

            // 查询代办任务计划完成时间
            $todoPlanEndTimeMap = [];
            if (!empty($todoTaskIds)) {
                $todoPlanEndTimeList = model(PlanModel::class)->where(['task_id' => ['IN', $todoTaskIds]])->field('task_id,end_time')->select();
                $todoPlanEndTimeMap = array_column($todoPlanEndTimeList, null, 'task_id');
            }
            // 查询标准任务计划完成时间
            if (!empty($stepEpisodeIds)) {
                //排期时间查询
                $planTimeMap = PlanService::getInstance()->getStepCategoryPlanEndTime($stepEpisodeIds, $stepCategoryIds);
            }
            foreach ($entityList as $entityItem) {
                $item = separate_complex_query_data($entityItem, '__');
                $taskJsonArr = json_decode($item['task']['json'], true);
                unset($item['task']['json']);
                if (!empty($taskJsonArr['is_dismantle_task'])) {
                    $item['entity']['name'] = $taskJsonArr['dismantle_name'];
                }
                $item['task']['task_status_id'] = $taskJsonArr['task_status'] ?? 0;

                if ($item['task']['step_type'] == TaskModel::STEP_TYPE_STEP) {
                    $item['plan']['end_time'] = empty($planTimeMap[$item['task']['episode_id']][$item['task']['step_category_id']]) ? 0 : $planTimeMap[$item['task']['episode_id']][$item['task']['step_category_id']];
                } else {
                    $item['plan']['end_time'] = $todoPlanEndTimeMap[$item['task']['id']]['end_time'] ?? '';
                }
                $entityMap[$item['task']['id']] = $item;
            }
        }

        $statusList = model(StatusModel::class)->select();
        $statusMap = array_column($statusList, null, 'id');
        return array_map(function ($taskWorkTimeRecordItem) use ($entityMap, $statusMap) {
            if ($taskWorkTimeRecordItem['module_id'] === module_by_code('task')['id']) {
                if (isset($entityMap[$taskWorkTimeRecordItem['link_id']])) {
                    $taskWorkTimeRecordItem = array_merge($taskWorkTimeRecordItem, $entityMap[$taskWorkTimeRecordItem['link_id']]);
                }
                if (!isset($entityMap[$taskWorkTimeRecordItem['link_id']])) {
                    $taskWorkTimeRecordItem["task_delete"] = "yes";
                }
                $taskWorkTimeRecordItem['project_id'] = $entityMap[$taskWorkTimeRecordItem['link_id']]['task']['project_id'] ?? 0;
                // 任务状态
                $entityMapTaskStatusKey = $entityMap[$taskWorkTimeRecordItem['link_id']]['task']['task_status_id'] ?? null;
                $taskWorkTimeRecordItem['status'] = $statusMap[$entityMapTaskStatusKey] ?? null;
                // 计划交付时间
                $taskWorkTimeRecordItem['task']['plan_delivery_time'] = $entityMap[$taskWorkTimeRecordItem['link_id']]['plan']['end_time'] ?? null;
            }
            // 换算两位
            $taskWorkTimeRecordItem["work_time"] = decimal_data($taskWorkTimeRecordItem["work_time"] / (60 * 60), 2);

            $workTimeType = WorkTimeRecordModel::TYPE_STANDARD_TASK; // 默认标准任务
            if (!empty($taskWorkTimeRecordItem['task']['entity_module_id'])) {
                if ($taskWorkTimeRecordItem['task']['entity_module_id'] == module_by_code('todo')['id'] && $taskWorkTimeRecordItem['task']['step_type'] != WorkTimeRecordModel::TYPE_WORK_ORDER_TO_DO) {
                    $workTimeType = WorkTimeRecordModel::TYPE_TO_DO; // 普通待办(不包括工单待办)
                }
                // 资产制作
                if (in_array($taskWorkTimeRecordItem['task']['entity_module_id'], [module_by_code('asset')['id'], module_by_code('design')['id'], module_by_code('level')['id']])) {
                    $workTimeType = WorkTimeRecordModel::TYPE_WORK_ORDER_ASSET;
                }
                // 镜头制作
                if (in_array($taskWorkTimeRecordItem['task']['entity_module_id'], [module_by_code('shot')['id'], module_by_code('storyboard')['id']])) {
                    $workTimeType = WorkTimeRecordModel::TYPE_WORK_ORDER_SHOT;
                }
                // 工单待办
                if ($taskWorkTimeRecordItem['task']['step_type'] == WorkTimeRecordModel::TYPE_WORK_ORDER_TO_DO) {
                    $workTimeType = WorkTimeRecordModel::TYPE_WORK_ORDER;
                }
                // 资产审核
                if ($taskWorkTimeRecordItem['type'] == WorkTimeRecordModel::TYPE_ASSET_REVIEW) {
                    $workTimeType = WorkTimeRecordModel::TYPE_ASSET_REVIEW;
                }
                // 镜头审核
                if ($taskWorkTimeRecordItem['type'] == WorkTimeRecordModel::TYPE_SHOT_REVIEW) {
                    $workTimeType = WorkTimeRecordModel::TYPE_SHOT_REVIEW;
                }
            }
            $taskWorkTimeRecordItem['type'] = $workTimeType;
            return $taskWorkTimeRecordItem;
        }, $workTimeRecordList);
    }

    /**
     * 获取任务工时记录
     * @param $taskId
     * @return array
     * @throws \think\Exception
     */
    public function getTaskWorkTimeRecord($taskId)
    {

        $workTimeRecordData = model(WorkTimeRecordModel::class)
            ->where(['link_id' => $taskId, 'module_id' => module_by_code('task')['id']])
            ->field("sum(work_time) as work_time_seconds,link_id,user_id")
            ->group('link_id,user_id')
            ->select();
        if (empty($workTimeRecordData)) {
            return [];
        }

        // 查询实体详情
        $entityData = model(TaskModel::class)->join("inner join entity e on task.entity_id = e.id")
            ->field("e.initial_episode_code,e.showings_number,e.name as entity_name,task.name as task_name,task.id as task_id")
            ->where(['task.id' => $taskId])
            ->find();
        if (empty($entityData)) {
            return [];
        }

        $userIds = unique_arr(array_column($workTimeRecordData, 'user_id'));
        $userInfoData = model(UserModel::class)->where(['id' => ['IN', $userIds]])->field('id,name,avatar')->select();
        $userInfoMap = array_column($userInfoData, null, 'id') ?? null;

        $list = array_map(function ($tmp) use ($userInfoMap, $entityData) {
            $hour = 0;
            if (!empty($tmp['work_time_seconds'])) {
                $hour = decimal_data($tmp['work_time_seconds'] / 3600, 2);
            }
            $tmp['work_time_hour'] = $hour;
            $tmp['user_name'] = $userInfoMap[$tmp['user_id']]['name'] ?? null;
            $tmp['avatar'] = $userInfoMap[$tmp['user_id']]['avatar'] ?? null;
            $tmp['entity_name'] = $entityData['initial_episode_code'] . '/' . $entityData['showings_number'] . '/' . $entityData['entity_name'] . '/' . $entityData['task_name'];
            return $tmp;
        }, $workTimeRecordData);

        $returnData['count_sum'] = array_sum(array_column($list, 'work_time_hour'));
        $returnData['list'] = $list;
        return $returnData;
    }

    /**
     * 记录工时
     * @param $data
     * @return array|bool|int|string
     * @throws \think\Exception
     * @throws \Exception
     */
    public function recordWorkTime($data)
    {
        $specifiedDate = $data["specified_date"];
        $onDutyDate = $data["on_duty_date"];
        $offDutyDate = $data["off_duty_date"];
        $tenantId = $data["tenant_id"];
        $unionId = $data["union_id"];

        APP_DEBUG && trace("接受考勤数据推送" . json_encode($data, true), "ERR");
        // 中间休息时段
        $rests = $data["shift_query_rests"][0]["sections"][0]["rests"] ?? [];

        // 转换为当天 , 获取上班时间段
        $workingHours = [];
        if (!empty($rests)) {
            foreach ($rests as $restsItem) {
                $currentTime = date('Y-m-d', $specifiedDate) . " " . date("H:i:s", strtotime($restsItem["check_time"]));
                if ($restsItem["check_type"] === "OnDuty") {
                    $workingHours[] = [
                        'start_time' => $onDutyDate,
                        'end_time' => strtotime($currentTime)
                    ];
                }

                if ($restsItem["check_type"] === "OffDuty") {
                    $workingHours[] = [
                        'start_time' => strtotime($currentTime),
                        'end_time' => $offDutyDate
                    ];
                }
            }
        } else {
            $workingHours[] = [
                'start_time' => $onDutyDate,
                'end_time' => $offDutyDate
            ];
        }

        $user = model(UserModel::class)->where(['union_id' => $unionId])->find();
        if (empty($user)) {
            throw new LogicException("user not found", ErrorCode::USER_NOT_FOUND);
        }
        $userId = $user['id'];
        $time = strtotime(date('Y-m-d', $specifiedDate));
        $nextTime = strtotime("+1 day", $time);

        //如果该天内记录再次打卡将不在计算新开始的
        $workTimeRecordExist = model(WorkTimeRecordModel::class)->where(['user_id' => $userId, 'record_time' => $time])->find();
        if (!empty($workTimeRecordExist)) {
            return [];
        }

        $timeLogList = model(TimelogModel::class)->where([
            'created_by' => $userId,
            'module_id' => module_by_code('task')['id'],
            '_string' => "start_time >= {$time} and start_time < {$nextTime}"
        ])->select();

        if (empty($timeLogList)) {
            return [];
        }

        $inProcessTimeLog = null;
        foreach ($timeLogList as $timeLogItem) {
            if ($timeLogItem["complete"] == "no") {
                $inProcessTimeLog = $timeLogItem;
            }
        }

        $timeLogList = array_column($timeLogList, null, 'id');

        // 停止正在做的任务
        if (!empty($inProcessTimeLog)) {
            $res = TimelogService::getInstance()->stopTimer(["id" => $inProcessTimeLog["id"], "end_time" => date('Y-m-d H:i:s', $offDutyDate)]);
            $timeLogList[$res['id']] = $res;
        }

        $taskIds = [];
        foreach ($timeLogList as $timeLogItem) {
            $taskIds[$timeLogItem['link_id']] = $timeLogItem['link_id'];
        }

        $taskIds = array_values($taskIds);
        $taskList = model(TaskModel::class)
            ->join("entity on entity.id = task.entity_id", "LEFT")
            ->where(['task.id' => ['IN', $taskIds]])
            ->field("task.id,task.name as task_name,entity.project_id,entity.initial_episode_code,entity.showings_number,entity.name")->select();
        $taskList = array_column($taskList, null, 'id');

        // 合计时间
        $workTimeRecordData = [];
        $workTimeRecordWhere = [];
        $timeLogType = 'standard_task';
        foreach ($timeLogList as $timeLogItem) {
            $workTime = null;
            //如有超出部分 ,则截取部分. 全部超出, 将不记录
            foreach ($workingHours as $workingHoursItem) {
                if ($timeLogItem['start_time'] < $workingHoursItem["end_time"]) {
                    $currentEndTime = $timeLogItem['end_time'] > $workingHoursItem["end_time"] ? $workingHoursItem["end_time"] : $timeLogItem['end_time'];
                } else {
                    continue;
                }

                if ($timeLogItem['end_time'] > $workingHoursItem["start_time"]) {
                    $currentStartTime = $timeLogItem['start_time'] < $workingHoursItem["start_time"] ? $workingHoursItem["start_time"] : $timeLogItem['start_time'];
                } else {
                    continue;
                }
                if (!isset($workTime)) {
                    $workTime = $currentEndTime - $currentStartTime;
                } else {
                    $workTime += ($currentEndTime - $currentStartTime);
                }
            }

            if (!isset($workTime)) {
                continue;
            }

            $key = join("_", [$timeLogItem['link_id'], $timeLogItem['tenant_id'], $timeLogType, $timeLogItem['module_id'], $userId, $time]);

            //可能存在任务被删除,任务被删除直接跳过
            if (!isset($taskList[$timeLogItem['link_id']])) {
                continue;
            }

            if (!isset($workTimeRecordData[$key])) {
                $workTimeRecordWhere[] = [
                    'link_id' => $timeLogItem['link_id'],
                    'tenant_id' => $timeLogItem['tenant_id'],
                    'type' => $timeLogType,
                    'module_id' => $timeLogItem['module_id'],
                    'user_id' => $userId,
                    'record_time' => $time
                ];

                $taskName = join("/", array_filter([
                    $taskList[$timeLogItem['link_id']]['initial_episode_code'],
                    $taskList[$timeLogItem['link_id']]['showings_number'],
                    $taskList[$timeLogItem['link_id']]['name'],
                    $taskList[$timeLogItem['link_id']]['task_name'],
                ], function ($taskNameItem) {
                    return !empty($taskNameItem);
                }));

                $workTimeRecordData[$key] = [
                    'name' => $taskName,
                    'link_id' => $timeLogItem['link_id'],
                    'tenant_id' => $timeLogItem['tenant_id'],
                    'type' => $timeLogType,
                    'module_id' => $timeLogItem['module_id'],
                    'project_id' => $taskList[$timeLogItem['link_id']]['project_id'] ?? 0,
                    'user_id' => $userId,
                    'record_time' => $time,
                    'work_time' => $workTime,
                    'created' => time(),
                    'updated' => time()
                ];
            } else {
                $workTimeRecordData[$key]['work_time'] = $workTimeRecordData[$key]['work_time'] + $workTime;
            }
        }

        if (!empty($workTimeRecordData)) {
            $workTimeRecordWhere["_logic"] = "OR";
            $existWorkTimeRecordList = model(WorkTimeRecordModel::class)->where($workTimeRecordWhere)->select();
            // 同一天内 同个模块任务工时记录 只能有一个
            $existWorkTimeRecordMap = [];
            foreach ($existWorkTimeRecordList as $existWorkTimeRecordItem) {
                $key = join("_", [
                    $existWorkTimeRecordItem['link_id'],
                    $existWorkTimeRecordItem['tenant_id'],
                    $existWorkTimeRecordItem['type'],
                    $existWorkTimeRecordItem['module_id'],
                    $existWorkTimeRecordItem['user_id'],
                    $existWorkTimeRecordItem['record_time']
                ]);
                $existWorkTimeRecordMap[$key] = $existWorkTimeRecordItem;
            }

            //比较出多余的
            $diffWorkTimeRecordData = array_diff_key($workTimeRecordData, $existWorkTimeRecordMap);
            if ($diffWorkTimeRecordData) {
                $diffWorkTimeRecordData = array_values($diffWorkTimeRecordData);
                return model(WorkTimeRecordModel::class)->addAll($diffWorkTimeRecordData);
            }
        }
        return [];
    }

    /**
     * 更新工时记录
     * @param $data
     * @return array|bool
     * @throws \Exception
     */
    public function updateWorkTimeRecord($data)
    {
        $data['record_time'] = strtotime(date("Y-m-d", $data['record_time']));
        $recordTime = $data['record_time'];
        $userId = $data['user_id'];
        $tenantId = $data['tenant_id'];
        $startTime = $recordTime;
        $endTime = strtotime("+1 day", $startTime) - 1;
        $user = model(UserModel::class)->find($userId);

        // 标准任务已播出的锁定
        $standardTaskList = [
            WorkTimeRecordModel::TYPE_STANDARD_TASK,
            WorkTimeRecordModel::TYPE_SHOT_REVIEW,
            WorkTimeRecordModel::TYPE_ASSET_REVIEW,
            WorkTimeRecordModel::TYPE_WORK_ORDER_ASSET,
            WorkTimeRecordModel::TYPE_WORK_ORDER_SHOT
        ];

        if (in_array($data['type'], $standardTaskList)) {
            $taskData = model(TaskModel::class)->where(['id' => $data['link_id']])->field('episode_id')->find();
            if (!empty($taskData['episode_id'])) {
                $episodeData = model(EntityModel::class)->where(['id' => $taskData['episode_id']])->field("json->>'$.episode_show_time' as episode_show_time")->find();
                if (!empty($episodeData['episode_show_time'])) {
                    throw_strack_exception('Episode is show !', ErrorCode::EPISODE_IS_SHOW);
                }
            }
        }

        // 可修改时长限制
        $workTimeRecord = [];
        if (!empty($data['work_time'])) {
            $workHourList = teamones_request('teamones-work-hour', 'dingtalk/get_user_work_times', [
                "user_id_list" => [$user['union_id']],
                "tenant_id" => $tenantId,
                "work_date_from" => date('Y-m-d H:i:s', $startTime),
                "work_date_to" => date('Y-m-d H:i:s', $endTime)
            ]);


            $workHour = $workHourList["data"][0]["work_every_day_min"][$startTime] ?? [];
            if (empty($workHour)) {
                throw new LogicException("not checked in the day", ErrorCode::NOT_CHECKED_IN_THE_DAY);
            }
            $workHour = $workHour * 60;
            $workTimeRecordList = model(WorkTimeRecordModel::class)->where([
//                'tenant_id' => $tenantId, // 合并用户在其他租户的工时统计
                'user_id' => $userId,
                'record_time' => $recordTime
            ])->select();
            $workTimeList = [];

            foreach ($workTimeRecordList as $workTimeRecordListItem) {
                $workTimeList[] = $workTimeRecordListItem["work_time"]; // 当前用户当天所有记录的工时
                // 版本迭代后没有标准任务,兼容历史数据的标准任务类型,资产审核、镜头审核、资产制作、镜头制作都属于标准任务
                $type = [$workTimeRecordListItem["type"]];
                if (in_array($workTimeRecordListItem['type'], $standardTaskList)) {
                    $type = [WorkTimeRecordModel::TYPE_STANDARD_TASK, $data['type']];
                }
                // 判断同一个用户,同一个模块下,同一天是否记录过工时
                if ($data['link_id'] == $workTimeRecordListItem["link_id"] &&
//                    $data['tenant_id'] == $workTimeRecordListItem["tenant_id"] && // 合并用户在其他租户的工时统计,所以去掉租户查询条件
                    in_array($data['type'], $type) &&
                    $data['module_id'] == $workTimeRecordListItem["module_id"] &&
                    $data['user_id'] == $workTimeRecordListItem["user_id"] &&
                    $data['record_time'] == $workTimeRecordListItem["record_time"] // 当前日期是否记录
                ) {
                    $workTimeRecord = $workTimeRecordListItem;
                }
            }
            // 判断新记录的工时有没有超出可记录工时
            $sumWorkTime = array_sum($workTimeList);
            $remainingTime = (decimal_data($workHour / (60 * 60), 2) - decimal_data($sumWorkTime / (60 * 60), 2)) * (60 * 60);
            $remainingTime = intval(ceil($remainingTime));
            $updateTime = intval($data['work_time']);
            if (!empty($workTimeRecord)) {
                $updateTime = $updateTime - $workTimeRecord["work_time"];
            }
            if ($updateTime > $remainingTime) {
                throw new LogicException("allotted time can not exceed remaining time", ErrorCode::ALLOTTED_TIME_CAN_NOT_EXCEED_REMAINING_TIME);
            }
        } else {
            $type = $data['type'];
            if (in_array($type, $standardTaskList)) {
                $type = ['IN', [WorkTimeRecordModel::TYPE_STANDARD_TASK, $type]];
            }
            $workTimeRecord = model(WorkTimeRecordModel::class)->where([
                'link_id' => $data['link_id'],
                'tenant_id' => $data['tenant_id'],
                'type' => $type,
                'module_id' => $data['module_id'],
                'user_id' => $data['user_id'],
                'record_time' => $data['record_time']
            ])->find();
        }


        // 查询任务信息
        $taskData = model(EntityModel::class)
            ->join('task on entity.id = task.entity_id', 'RIGHT')
            ->where(['task.id' => ['EQ', $data['link_id']]])
            ->field('task.type,task.project_id,entity.name as entity_name,task.name as task_name,entity.initial_episode_code,entity.showings_number,task.step_type,task.json as task_json')
            ->find();

        if (empty($taskData)) {
            return [];
        }

        // 记录项目 ID
        if (!empty($taskData['project_id'])) {
            $data['project_id'] = $taskData['project_id'];
        }

        if (!empty($workTimeRecord)) {
            $data['id'] = $workTimeRecord['id'];
            $returnData = model(WorkTimeRecordModel::class)->modifyItem($data);
        } else {
            $returnData = model(WorkTimeRecordModel::class)->addItem($data);
        }
        if (empty($returnData['link_id'])) {
            return $returnData;
        }

        $taskJsonArr = json_decode($taskData['task_json'], true);
        if (!empty($taskJsonArr['is_dismantle_task'])) {
            $taskData['entity_name'] = $taskJsonArr['dismantle_name'];
        }

        // 剧集/场次/名字/工序
        if ($taskData['step_type'] == 'to_do') {
            $taskName = $taskData['task_name'];
        } else if ($taskData['step_type'] == 'work_order_to_do') {
            $taskName = $taskData['task_name'];
        } else {
            $taskName = $taskData['initial_episode_code'] . '/' . $taskData['showings_number'] . '/' . $taskData['entity_name'] . '/' . $taskData['task_name'];
        }
        $returnData['name'] = $taskName;
        $returnData['entity']['name'] = $taskName; // 兼容前端任务显示空白问题
        return $returnData;
    }

    /**
     * 获取天的工时记录
     * @param $filter
     * @param array $page
     * @param array $departmentUserList
     * @return array
     */
    public function getDayWorkTimeRecordList($filter, $page = [], $departmentUserList = [])
    {
        // 获取到每天的工作时长
        $startTime = strtotime(date('Y-m-d', strtotime($filter["start_time"])));
        $endTime = strtotime("+1 day", strtotime(date('Y-m-d', strtotime($filter["end_time"])))) - 1; //计算到末尾时间

        // 时间分页
        $limitTimeRange = [];
        $currentTime = strtotime(date('Y-m-d', $startTime));
        if ($currentTime > 0 && $endTime > 0 && $endTime >= $currentTime) {
            if ($currentTime == $startTime) {
                $limitTimeRange[] = $currentTime;
            }
            $currentTime = strtotime("+1 day", $currentTime);
            while ($currentTime <= $endTime) {
                $limitTimeRange[] = $currentTime;
                $currentTime = strtotime("+1 day", $currentTime);
            }
        }
        if (!empty($limitTimeRange) && !empty($page[0]) && !empty($page[1])) {
            $limit = $page[1] * ($page[0] - 1);
            $pageSize = $page[1];
            if (empty($limitTimeRange[$limit]) && empty($limitTimeRange[($limit + $pageSize) - 1])) {
                return [];
            }
            $startTime = $limitTimeRange[$limit];
            $endTime = $limitTimeRange[($limit + $pageSize) - 1] ?? $endTime;
        }
        unset($limitTimeRange);

        $userId = $filter["user_id"];
        $tenantId = $filter["tenant_id"];
        $projectId = $filter["project_id"] ?? [];
        $user = model(UserModel::class)->find($userId);

        // 默认按照个人统计
        $imUserIds = [$user['union_id']];
        // 如果有部门统计,则按照部门统计
        if (!empty($departmentUserList)) {
            $imUserIds = array_column($departmentUserList, 'im_user_id');
            $userId = ['IN', array_column($departmentUserList, 'saas_user_id')];
        }

        $workHourList = teamones_request('teamones-work-hour', 'dingtalk/get_user_work_times', [
            "user_id_list" => $imUserIds,
            "tenant_id" => $tenantId,
            "work_date_from" => date('Y-m-d H:i:s', $startTime),
            "work_date_to" => date('Y-m-d H:i:s', $endTime)
        ]);

        $WorkTimeRecordFilter = [
            'user_id' => $userId,
//            'tenant_id' => $tenantId, // 增加用户在其他租户的工时统计,所以去掉租户查询条件
            'record_time' => ["BETWEEN", [$startTime, $endTime]]
        ];

        if (!empty($projectId)) {
            $WorkTimeRecordFilter["project_id"] = $projectId;
        }

        $workHourList = $workHourList["data"] ?? [];

        $workEveryDayHour = [];
        $tmpWorkEveryDayHour = [];
        $tmpWorkEveryDayHourList = [];
        foreach ($workHourList as $workHourItem) {
            if ($workHourItem["user_id"] == $user['union_id']) {
                $workEveryDayHour = $workHourItem["work_every_day_min"];
            }
            if (!empty($departmentImUserIds)) {
                if (in_array($workHourItem['user_id'], $departmentImUserIds)) {
                    foreach ($workHourItem['work_every_day_min'] as $k => $v) {
                        $tmpWorkEveryDayHour[$k][] = (float)$v ?? 0;
                    }
                }
                foreach ($tmpWorkEveryDayHour as $key => $hourArr) {
                    $tmpWorkEveryDayHourList[$key] = $hourArr;
                }
                foreach ($tmpWorkEveryDayHourList as $listKey => $hourListArr) {
                    $tmpWorkEveryDayHourList[$listKey] = array_sum($hourListArr);
                }
                $workEveryDayHour = $tmpWorkEveryDayHourList;
            }
        }
        $workEveryDayHour = array_filter($workEveryDayHour, function ($workEveryDayHourItem) {
            return intval($workEveryDayHourItem) > 0;
        });

        // 获取时间段内,记录每天
        $scopeDay = [];
        $currentTime = strtotime(date('Y-m-d', $startTime));
        if ($currentTime > 0 && $endTime > 0 && $endTime >= $currentTime) {
            if ($currentTime == $startTime) {
                $scopeDay[] = $currentTime;
            }
            $currentTime = strtotime("+1 day", $currentTime);
            while ($currentTime <= $endTime) {
                $scopeDay[] = $currentTime;
                $currentTime = strtotime("+1 day", $currentTime);
            }
        }
        $taskModuleId = module_by_code('task')['id'];
        $workTimeRecord = model(WorkTimeRecordModel::class)->alias('wtr')
            ->join('task on task.id = wtr.link_id and wtr.module_id = ' . $taskModuleId) ## join task 表,防止查询到废除的任务
            ->where($WorkTimeRecordFilter)
            ->field('wtr.tenant_id,wtr.record_time,wtr.work_time') // 查询指定时间范围的工时记录情况
            ->select();

        $tenantFilter = [
            "param" => [
                "filter" => [
                    "tenant.id" => ["-in", join(',', array_column($workTimeRecord, 'tenant_id'))]
                ],
                "fields" => "id,name"
            ]
        ];
        $tenantService = TenantService::getInstance();
        $tenantList = $tenantService->tenantSelect($tenantFilter);
        $tenantMap = array_column($tenantList, null, 'id');

        $workTimeRecordCount = []; // 当前租户的工时记录
        $otherWorkTimeRecordCount = []; // 其他租户的工时记录
        foreach ($workTimeRecord as $workTimeRecordItem) {
            $currentRecordTime = strtotime(date('Y-m-d', $workTimeRecordItem['record_time']));
            if ($workTimeRecordItem['tenant_id'] == $tenantId) {
                if (!isset($workTimeRecordCount[$currentRecordTime])) {
                    $workTimeRecordCount[$currentRecordTime] = $workTimeRecordItem['work_time'];
                } else {
                    $workTimeRecordCount[$currentRecordTime] += $workTimeRecordItem['work_time'];
                }
            } else {
                $otherWorkTimeRecordCount[$currentRecordTime][] = [
                    'name' => $workTimeRecordItem['tenant_id'],
                    'tenant_id' => $workTimeRecordItem['tenant_id'],
                    'duration' => $workTimeRecordItem['work_time']
                ];
            }
        }

        $otherWorkTimeRecordCountMap = [];
        if (!empty($otherWorkTimeRecordCount)) {
            foreach ($otherWorkTimeRecordCount as $currentRecordTime => $otherWorkTimeItem) {
                $tmpVal = [];
                foreach ($otherWorkTimeItem as $val) {
                    if (empty($val['duration'])) {
                        continue;
                    }
                    if (!isset($tmpVal[$val['tenant_id']])) {
                        $tmpVal[$val['tenant_id']] = [
                            'name' => $tenantMap[$val['tenant_id']]['name'] ?? "",
                            'tenant_id' => $val['tenant_id'],
                            'duration' => $val['duration']
                        ];
                    } else {
                        $tmpVal[$val['tenant_id']]['duration'] += $val['duration'];
                    }
                }
                $tmpValue = [];
                foreach ($tmpVal as $v) {
                    $tmpValue[] = ['name' => $v['name'], 'duration' => decimal_data($v['duration'] / (60 * 60), 2), 'tenant_id' => $val['tenant_id']];
                }
                $otherWorkTimeRecordCountMap[$currentRecordTime] = $tmpValue;
            }
        }

        $workTimeRecordResult = [];
        foreach ($scopeDay as $scopeDayItem) {
            $workTimeRecordResult[] = [
                'time' => $scopeDayItem,
                'format_ymd_time' => date("Y-m-d", $scopeDayItem),
                'status' => isset($workEveryDayHour[$scopeDayItem]) ? 'normal' : "miss_card",
                'work_duration' => isset($workEveryDayHour[$scopeDayItem]) ? decimal_data($workEveryDayHour[$scopeDayItem] / 60, 2) : null,
                'task_duration' => isset($workTimeRecordCount[$scopeDayItem]) ? decimal_data($workTimeRecordCount[$scopeDayItem] / (60 * 60), 2) : null,
                'other_task_duration' => $otherWorkTimeRecordCountMap[$scopeDayItem] ?? null,
            ];
        }
        unset($scopeDay);
        return $workTimeRecordResult;
    }

    /**
     * 获取指定日期的工时
     * @param $filter
     * @return array|null[]
     * @throws \Exception
     */
    public function getSpecifiedDayWorkTime($filter)
    {
        $filter['specified_date'] = $filter['specified_date'] ?? time();
        $specifiedDate = strtotime(date('Y-m-d', strtotime($filter['specified_date'])));
        unset($filter['specified_date']);

        $startTime = $specifiedDate;
        $endTime = strtotime("+1 day", $startTime) - 1;
        $filter['start_time'] = $filter['start_time'] ?? date('Y-m-d', $startTime);
        $filter['end_time'] = $filter['end_time'] ?? date('Y-m-d', $endTime);
        $userId = $filter['user_id'];

        $workTime = [
            'time' => $specifiedDate,
            'status' => "miss_card",
            'work_duration' => null,
            'task_duration' => null,
            'user' => null
        ];

        // 部门统计
        $departmentUserList = [];
        if (!empty($filter['department_id'])) {
            $departmentUserList = DepartmentReportService::getInstance()->getDepartmentUserList($filter['department_id']);
            if (empty($departmentUserList)) { // 没有查到当前部门下的用户
                return [];
            }
        }

        $result = $this->getDayWorkTimeRecordList($filter, [], $departmentUserList);

        if (empty($result)) {
            $result = $workTime;
        } else {
            // 兼容个人工时迭代,增加时间区间筛选汇总
            if (count($result) > 1) {
                $result = [
                    'time' => 0,
                    'status' => '',
                    'user' => null,
                    'work_duration' => array_sum(array_column($result, 'work_duration')),
                    'task_duration' => array_sum(array_column($result, 'task_duration')),
                    'other_task_duration' => array_sum(array_column($result, 'other_task_duration'))
                ];
            } else {
                $result = $result[0];
                $result['user'] = model(UserModel::class)->field("id,name,avatar")->find($userId);
            }
        }
        return $result;
    }

    /**
     * 工时记录任务搜索
     * @param $filter
     * @param $page
     * @param $userId
     * @param $tenantId
     * @return array
     * @throws Exception
     */
    public function taskSearch($filter, $page, $userId, $tenantId)
    {
        $date = $filter['date'] ?? '';  // 查询哪一天
        $isStandard = $filter['is_standard'] ?? false;
        $searchName = $filter['search_name'] ?? '';
        $statusList = model(StatusModel::class)->select();
        // 查询标准任务
        $standardIdList = $this->getStandardTaskList($userId, $tenantId, $isStandard, $statusList, $searchName);

        // 查询代办任务
        $taskMemberIdList = $this->getMemberTask($userId, $tenantId, $statusList, $searchName);

        $standardTodoTaskIds = array_merge($taskMemberIdList, $standardIdList); // 组装待办任务和标准任务

        unset($filter['is_standard'], $filter['search_name'], $filter['date']);
        $memberAndStandardTaskList = $this->getMemberAndStandardTaskList($userId, $tenantId, $statusList, $standardTodoTaskIds, $page, $date, $filter, $searchName, 'standardAndReviewTask.task__step_type,standardAndReviewTask.task__plan_end_time ASC');
        if (empty($memberAndStandardTaskList)) {
            return [];
        }
        // 查任务总记录的工时
        $workTimeList = model(WorkTimeRecordModel::class)
            ->where(['link_id' => ['IN', join(',', $standardTodoTaskIds)]])
            ->where('work_time > 0')
            ->field('sum(work_time) as work_time_sum,link_id')
            ->group('link_id')
            ->select();

        $workTimeMap = array_column($workTimeList, null, 'link_id');
        return array_map(function ($tmp) use ($workTimeMap) {
            $workTimeSum = intval($workTimeMap[$tmp['task']['id']]['work_time_sum'] ?? 0);
            $tmp['work_time_sum'] = decimal_data($workTimeSum / (60 * 60), 2);
            return $tmp;
        }, $memberAndStandardTaskList);
    }

    /**
     * 获取标准任务
     * @param $userId
     * @param $tenantId
     * @param $isStandard
     * @param $statusList
     * @param $searchName
     * @return array
     * @throws Exception
     */
    public function getStandardTaskList($userId, $tenantId, $isStandard, $statusList, $searchName)
    {
        // 搜索标准任务
        if (!empty($searchName)) {
            $standardTaskWhere[] = [
                'entity.name' => ['LIKE', '%' . $searchName . '%'],
                'entity.code' => ['LIKE', '%' . $searchName . '%'],
                'task.name' => ['LIKE', '%' . $searchName . '%'],
                '_logic' => "OR"
            ];
        }
        // 标准任务
        $statusMap = array_column($statusList, null, 'code');
        $standardTaskWhere[] = ['task.tenant_id' => $tenantId, 'task.executor' => $userId];
        if ($isStandard) {
            $filterStatusIds =
                [
                    $statusMap['final']['id'], // 已完成 final
                    $statusMap['ready_to_publish']['id'], // 待发布 ready_to_publish
                    $statusMap['submitted']['id'], //  审核中 submitted
                    $statusMap['wait_for_party_a_review']['id'] // 待甲方审核 wait_for_party_a_review
                ];
            if (!empty($filterStatusIds)) {
                $standardTaskWhere[] = [
                    "JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NOT IN', join(',', $filterStatusIds)]
                ];
            }

            $timeLog = model(TimelogModel::class)->findData([
                'filter' => [
                    'module_id' => Module::$moduleDictData['module_index_by_code']['task']['id'],
                    'created_by' => $userId,
                    'tenant_id' => $tenantId,
                ],
                'order' => 'id DESC',
            ]);
            if (!empty($timeLog)) {
                $detailData = TimelogService::getInstance()->queryTimeLogDetailData(['timelog.id' => $timeLog['id']]);
                if (!empty($detailData)) {
                    $standardTaskWhere[] = [
                        'task.id' => ['NEQ', $detailData[0]['task']['id']]
                    ];
                }
            }
        }
        $standardIdList = [];
        $standardList = model(EntityModel::class)
            ->join('task on entity.id = task.entity_id', 'INNER')
            ->where($standardTaskWhere)
            ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $statusMap['closed']['id']]])
            ->field('task.id')
            ->select();
        if (!empty($standardList)) {
            $standardIdList = array_column($standardList, 'id');
        }
        return $standardIdList;
    }

    /**
     * 获取待办任务
     * @param $userId
     * @param $tenantId
     * @param $statusList
     * @param $searchName
     * @return array
     * @throws Exception
     */
    public function getMemberTask($userId, $tenantId, $statusList, $searchName)
    {
        // 查询代办任务
        $taskMemberWhere[] = ['partner' => $userId];
        if (!empty($searchName)) {
            $taskMemberWhere[] = [
                'entity.name' => ['LIKE', '%' . $searchName . '%'],
                'entity.code' => ['LIKE', '%' . $searchName . '%'],
                'task.name' => ['LIKE', '%' . $searchName . '%'],
                '_logic' => "OR"
            ];
        }
        $taskMemberIdList = [];
        $statusMap = array_column($statusList, null, 'code');

        // 过滤掉正在进行中的待办任务
        $timeLog = model(TimelogModel::class)->findData([
            'filter' => [
                'module_id' => Module::$moduleDictData['module_index_by_code']['task']['id'],
                'created_by' => $userId,
                'tenant_id' => $tenantId,
            ],
            'order' => 'id DESC',
        ]);
        if (!empty($timeLog)) {
            $detailData = TimelogService::getInstance()->queryTimeLogDetailData(['timelog.id' => $timeLog['id']]);
            if (!empty($detailData)) {
                $taskMemberWhere[] = [
                    'task.id' => ['NEQ', $detailData[0]['task']['id']]
                ];
            }
        }

        $taskMemberList = model(TaskMemberModel::class)
            ->join("task on task.id = task_member.task_id")
            ->join('entity on entity.id = task.entity_id', 'LEFT')
            ->where($taskMemberWhere)
            ->where(['task_member.status' => ['NEQ', $statusMap['closed']['id']]])
            ->where(['task.tenant_id' => $tenantId])
            ->field('task.id,task.name')
            ->select();

        if (!empty($taskMemberList)) {
            $taskMemberIdList = array_column($taskMemberList, 'id');
        }
        return $taskMemberIdList;
    }

    /**
     * 获取个人标准任务和待办任务
     * @param $userId
     * @param $tenantId
     * @param $statusList
     * @param $standardTodoTaskIds
     * @param $page
     * @param $date
     * @param $filter
     * @param $searchName
     * @param $order
     * @return array|false|mixed|string
     */
    public function getMemberAndStandardTaskList($userId, $tenantId, $statusList, $standardTodoTaskIds, $page, $date, $filter, $searchName, $order)
    {
        if (!empty($filter['project.id'])) {
            $filter['task.project_id'] = $filter['project.id'];
            unset($filter['project.id']);
        }
        // 查询当天工作记录,过滤当天已经修正过的任务
        if (!empty($date)) {
            $time = strtotime(date('Y-m-d', strtotime($date)));
            $nextTime = strtotime("+1 day", $time);
            $workTimeRecordFilter = [
                'user_id' => $userId,
                'tenant_id' => $tenantId,
                '_string' => "record_time >= {$time} and record_time < {$nextTime} and link_id !=0"
            ];
            $workTimeRecordList = model(WorkTimeRecordModel::class)->where($workTimeRecordFilter)->field("id,link_id,type")->select();
        }

        $notReviewTaskIds = [];
        $notStandardTodoTaskIds = [];
        if (!empty($workTimeRecordList)) {
            foreach ($workTimeRecordList as $item) {
                // 筛选已经修正过的标准任务和待办任务
                $standardTaskType = [
                    WorkTimeRecordModel::TYPE_TO_DO,
                    WorkTimeRecordModel::TYPE_STANDARD_TASK,
                    WorkTimeRecordModel::TYPE_WORK_ORDER,
                    WorkTimeRecordModel::TYPE_WORK_ORDER_ASSET,
                    WorkTimeRecordModel::TYPE_WORK_ORDER_SHOT
                ];
                if (in_array($item['type'], $standardTaskType)) {
                    $notStandardTodoTaskIds[] = $item['link_id'];
                }
                // 筛选已经修正过的审核任务
                if (in_array($item['type'], [WorkTimeRecordModel::TYPE_ASSET_REVIEW, WorkTimeRecordModel::TYPE_SHOT_REVIEW])) {
                    $notReviewTaskIds[] = $item['link_id'];
                }
            }
            // 过滤已经修正过的标准任务和待办任务
            $standardTodoTaskIds = array_filter($standardTodoTaskIds, function ($tmp) use ($notStandardTodoTaskIds) {
                return !in_array($tmp, $notStandardTodoTaskIds);
            });
        }
        // 任务类型筛选
        $workTimeType = $filter['work_time_type'] ?? [];
        unset($filter['work_time_type']);

        $fields = [
            "entity.id", "entity.name", "entity.code", "entity.initial_episode_code", "entity.showings_number", "entity.module_id",
            "entity.end_time", "entity.project_id",
            "task.id", "task.name", "task.code", "task.man_hour", "task.frame_range", "task.timecode", "task.type",
            "task.step_type", "task.step_category_id", "task.step_id", "task.plan_start_time", "task.plan_end_time",
            "task.entity_module_id", "task.json", 'task.end_time', 'task.episode_id',
            'module.id', 'module.name', 'module.code'
        ];
        $statusMap = array_column($statusList, null, 'code');
        $statusIdMap = array_column($statusList, null, 'id');

        // 查询标准任务和待办任务
        if (!empty($searchName)) {
            $filter[] = [
                'entity.name' => ['LIKE', '%' . $searchName . '%'],
                'entity.code' => ['LIKE', '%' . $searchName . '%'],
                'task.name' => ['LIKE', '%' . $searchName . '%'],
                '_logic' => "OR"
            ];
        }
        $standardTodoTaskSql = model(EntityModel::class)
            ->join('task on entity.id = task.entity_id', 'RIGHT')
            ->join('module on task.entity_module_id = module.id')
            ->where($filter)
            ->where(['task.id' => ['IN', join(',', $standardTodoTaskIds)]])
            ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $statusMap['closed']['id']]])
            ->field(array_merge(build_complex_query_fields($fields, '__'), ['false as is_review']))
            ->buildSql();
        unset($filter['task.entity_module_id']);

        // 查询审核任务
        if (!empty($notReviewTaskIds)) {
            // 过滤掉已经记录过工时的数据
            $filter['task.id'] = ['NOT IN', $notReviewTaskIds];
        }
        $reviewRequestSql = model(ReviewRequestModel::class)
            ->join('review_request_node on review_request.id = review_request_node.review_request_id and review_request.module_id = ' . module_by_code('version')['id'])
            ->join('join version on version.id = review_request.link_id')
            ->join('INNER JOIN task on task.id = version.link_id and version.module_id = ' . module_by_code('task')['id'])
            ->join('entity on entity.id = task.entity_id')
            ->join('module on task.entity_module_id = module.id')
            ->where($filter)
            ->where(['review_request_node.plan_reviewer' => $userId])
            ->where(["JSON_UNQUOTE(JSON_EXTRACT(task.json,'$.task_status'))" => ['NEQ', $statusMap['closed']['id']]])
            ->group('task.id')
            ->field(array_merge(build_complex_query_fields($fields, '__'), ['true as is_review']))
            ->buildSql();

        $where = null;
        if (!empty($workTimeType)) {
            $where = 'where ';
            $assetIdList = [module_by_code('asset')['id'], module_by_code('design')['id'], module_by_code('level')['id']];
            $shotIdList = [module_by_code('shot')['id'], module_by_code('storyboard')['id']];
            $todoId = module_by_code('todo')['id'];
            $workOrderTodo = WorkTimeRecordModel::TYPE_WORK_ORDER_TO_DO;
            $assetIds = join(',', $assetIdList);
            $shotIdIds = join(',', $shotIdList);
            // 资产制作
            if (in_array(WorkTimeRecordModel::TYPE_WORK_ORDER_ASSET, $workTimeType)) {
                $where .= "(standardAndReviewTask.is_review = false and (standardAndReviewTask.task__entity_module_id in ({$assetIds}))) or ";
            }
            // 镜头制作
            if (in_array(WorkTimeRecordModel::TYPE_WORK_ORDER_SHOT, $workTimeType)) {
                $where .= "(standardAndReviewTask.is_review = false and (standardAndReviewTask.task__entity_module_id in ({$shotIdIds}))) or ";
            }
            // 镜头审核
            if (in_array(WorkTimeRecordModel::TYPE_SHOT_REVIEW, $workTimeType)) {
                $where .= "(standardAndReviewTask.is_review = true and (standardAndReviewTask.task__entity_module_id in ({$shotIdIds}))) or ";
            }
            // 资产审核
            if (in_array(WorkTimeRecordModel::TYPE_ASSET_REVIEW, $workTimeType)) {
                $where .= "(standardAndReviewTask.is_review = true and (standardAndReviewTask.task__entity_module_id in ({$assetIds}))) or ";
            }
            // 待办任务
            if (in_array(WorkTimeRecordModel::TYPE_TO_DO, $workTimeType)) {
                $where .= "(standardAndReviewTask.is_review = false and (standardAndReviewTask.task__entity_module_id = {$todoId}) and standardAndReviewTask.task__step_type !='{$workOrderTodo}') or ";
            }
            $where = trim($where, 'or ');
            if ($where == 'where') {
                $where = null;
            }
        }

        $limit = $page[1] * ($page[0] - 1);
        $pageSize = $page[1];
        $dataList = model(EntityModel::class)
            ->query("select * from ({$standardTodoTaskSql} UNION {$reviewRequestSql}) standardAndReviewTask {$where} order by {$order} limit {$limit},{$pageSize}");
        if (empty($dataList)) {
            return null;
        }

        $todoTaskIds = [];
        $stepEpisodeIds = [];
        $stepCategoryIds = [];
        $allStepCategoryIds = [];
        $projectIds = [];
        $stepIds = [];
        foreach ($dataList as &$item) {
            $item = separate_complex_query_data($item, '__');
            if ($item['task']['step_type'] == TaskModel::STEP_TYPE_STEP) {
                $stepEpisodeIds[] = $item['task']['episode_id'];
                $stepCategoryIds[] = $item['task']['step_category_id'];
            } else {
                $todoTaskIds[] = $item['task']['id'];
            }
            $stepIds[] = $item['task']['step_id'];
            $allStepCategoryIds[] = $item['task']['step_category_id'];
            $projectIds[] = $item['entity']['project_id'];
        }

        // 排期时间查询
        $planTimeMap = [];
        if (!empty($stepEpisodeIds) && !empty($stepCategoryIds)) {
            $planTimeMap = PlanService::getInstance()->getStepCategoryPlanEndTime($stepEpisodeIds, $stepCategoryIds);
        }
        $todoPlanEndTimeMap = [];
        if (!empty($todoTaskIds)) {
            $todoPlanEndTimeList = model(PlanModel::class)->where(['task_id' => ['IN', $todoTaskIds]])->field('task_id,end_time')->select();
            $todoPlanEndTimeMap = array_column($todoPlanEndTimeList, null, 'task_id');
        }
        // 查询工序/环节
        $stepCategoryList = model(StepCategoryModel::class)
            ->where(['step_category.id' => ['IN', $allStepCategoryIds]])
            ->field('step_category.id as step_category_id,step_category.name as step_category_name')
            ->select();
        $stepCategoryMap = [];
        if (!empty($stepCategoryList)) {
            $stepCategoryMap = array_column($stepCategoryList, null, 'step_category_id');
        }
        $stepList = model(StepModel::class)
            ->where(['step.id' => ['IN', $stepIds]])
            ->field('step.id as step_id,step.name as step_name')
            ->select();
        $stepMap = [];
        if (!empty($stepList)) {
            $stepMap = array_column($stepList, null, 'step_id');
        }
        $projectList = model(ProjectModel::class)->where(['id' => ['IN', $projectIds]])->field('id,name')->select();
        $projectMap = [];
        if (!empty($projectList)) {
            $projectMap = array_column($projectList, null, 'id');
        }
        foreach ($dataList as &$item) {
            $item = separate_complex_query_data($item, '__');
            $item['task']['task_module_id'] = module_by_code('task')['id'];
            $jsonArr = json_decode($item['task']['json'], true);
            $item['task']['is_dismantle_task'] = !empty($jsonArr['is_dismantle_task']); // 是否子任务
            $item['task']['dismantle_name'] = $jsonArr['dismantle_name'] ?? ''; // 子任务名称
            if ($item['task']['is_dismantle_task']) { // 如果是子任务的话,实体名称显示子任务名字
                $item['entity']['name'] = $item['task']['dismantle_name'];
            }
            $workTimeType = WorkTimeRecordModel::TYPE_STANDARD_TASK; // 默认标准修正任务类型
            if ($item['task']['entity_module_id'] == module_by_code('todo')['id'] && $item['task']['step_type'] != WorkTimeRecordModel::TYPE_WORK_ORDER_TO_DO) {
                $workTimeType = WorkTimeRecordModel::TYPE_TO_DO; // 普通待办(不包括工单待办)
            }
            // 资产制作
            if (in_array($item['task']['entity_module_id'], [module_by_code('asset')['id'], module_by_code('design')['id'], module_by_code('level')['id']])) {
                $workTimeType = WorkTimeRecordModel::TYPE_WORK_ORDER_ASSET;
            }
            // 镜头制作
            if (in_array($item['task']['entity_module_id'], [module_by_code('shot')['id'], module_by_code('storyboard')['id']])) {
                $workTimeType = WorkTimeRecordModel::TYPE_WORK_ORDER_SHOT;
            }
            if ($item['task']['step_type'] == WorkTimeRecordModel::TYPE_WORK_ORDER_TO_DO) {
                $workTimeType = WorkTimeRecordModel::TYPE_WORK_ORDER; // 工单待办
            }
            // 是否审核任务
            if ($item['is_review']) {
                // 资产
                if (in_array($item['task']['entity_module_id'], [module_by_code('asset')['id'], module_by_code('design')['id'], module_by_code('level')['id']])) {
                    $workTimeType = WorkTimeRecordModel::TYPE_ASSET_REVIEW;
                }
                // 镜头
                if (in_array($item['task']['entity_module_id'], [module_by_code('shot')['id'], module_by_code('storyboard')['id'], module_by_code('sequence')['id']])) {
                    $workTimeType = WorkTimeRecordModel::TYPE_SHOT_REVIEW;
                }
            }
            $item['task']['work_time_type'] = $workTimeType; // 工时修正类型
            // 状态
            $item['status'] = $statusIdMap[$jsonArr['task_status']] ?? [];
            // 计划交付时间
            if ($item['task']['step_type'] == TaskModel::STEP_TYPE_STEP) {
                $item['task']['plan_delivery_time'] = empty($planTimeMap[$item['task']['episode_id']][$item['task']['step_category_id']]) ? 0 : $planTimeMap[$item['task']['episode_id']][$item['task']['step_category_id']];
            } else {
                $item['task']['plan_delivery_time'] = $todoPlanEndTimeMap[$item['task']['id']]['end_time'] ?? 0;
            }

            // 环节
            $item['step_category'] = ['id' => $item['task']['step_category_id'] ?? 0, 'name' => $stepCategoryMap[$item['task']['step_category_id']]['step_category_name'] ?? null];
            $item['step'] = ['id' => $item['task']['step_id'] ?? 0, 'name' => $stepMap[$item['task']['step_id']]['step_name'] ?? null];
            $item['project'] = ['id' => $item['entity']['project_id'] ?? 0, 'name' => $projectMap[$item['entity']['project_id']]['name'] ?? null];

            unset($item['task']['json']);
        }
        return $dataList;
    }

    /**
     * 任务工时切换历史记录
     * @param $filter
     * @param $page
     * @param $userId
     * @param $tenantId
     * @return array
     */
    public function optionCheckHistoryList($filter, $page, $userId, $tenantId)
    {

        $statusList = model(StatusModel::class)->select();
        $timeLogList = model(TimelogModel::class)
            ->where(['module_id' => module_by_code('task')['id']])
            ->where(['tenant_id' => $tenantId, 'created_by' => $userId])
            ->field('link_id')
            ->page(1, 20)
            ->group('link_id')
            ->order('id desc')
            ->select();
        $historyTaskIds = array_column($timeLogList, 'link_id');
        return $this->getMemberAndStandardTaskList($userId, $tenantId, $statusList, $historyTaskIds, $page, '', $filter, '', 'standardAndReviewTask.task__id desc');
    }


    /**
     * 批量删除
     * @param $filter
     * @return array
     * @throws Exception
     */
    public function batchDelete($filter)
    {
        $workTimeRecordList = model(WorkTimeRecordModel::class)
            ->where($filter)->where(['work_time' => ['NEQ', 0]])->field('id')->select();
        if (empty($workTimeRecordList)) {
            return [];
        }
        $updateData = [];
        foreach ($workTimeRecordList as $item) {
            $updateData[] = [
                'id' => $item['id'],
                'work_time' => 0
            ];
        }
        // 软删除,把任务工时至为0
        return CommonService::instance('work_time_record')->commonBatchUpdate($updateData);
    }

    /**
     * 批量更新工时记录
     * @param $filter
     * @param $data
     * @param $userId
     * @param $tenantId
     * @return array|void
     * @throws Exception
     */
    public function batchUpdateWorkTimeRecord($filter, $data, $userId, $tenantId)
    {
        $workTimeRecordModel = model(WorkTimeRecordModel::class);
        $workTimeRecordList = $workTimeRecordModel->where($filter)->field('id,work_time')->select();
        if (empty($workTimeRecordList)) {
            throw_strack_exception('update work time fail !', ErrorCode::DELETE_WORK_TIME_FAIL);
        }
        $updateData = [];
        $workTimeRecordIds = [];
        foreach ($workTimeRecordList as $item) {
            if (empty($data['work_time'])) {
                continue;
            }
            $workTimeRecordIds[] = $item['id'];
            $updateData[] = [
                'id' => $item['id'],
                'work_time' => $data['work_time']
            ];
        }
        $recordTime = $startTime = $data['record_time'];
        $endTime = strtotime("+1 day", $startTime) - 1;
        // 是否超过当天可修改工时校验
        $checkStatus = $this->checkWorkHourLimit($userId, $startTime, $endTime, $tenantId, $recordTime, $workTimeRecordIds, $data['work_time']);
        if (!$checkStatus) {
            throw new LogicException("allotted time can not exceed remaining time", ErrorCode::ALLOTTED_TIME_CAN_NOT_EXCEED_REMAINING_TIME);
        }
        try {
            return CommonService::instance('work_time_record')->commonBatchUpdate($updateData, 'workTimeRecord', false);
        } catch (LogicException $e) {
            throw_strack_exception('update work time record fail:' . $e->getMessage(), ErrorCode::BATCH_UPDATE_WORK_TIME_FAIL);
        }
    }

    /**
     * 检查批量修改工时是否超过可记录工时
     * @param $userId
     * @param $startTime
     * @param $endTime
     * @param $tenantId
     * @param $recordTime
     * @param $workTimeRecordIds
     * @param $updateTime
     * @return bool
     */
    public function checkWorkHourLimit($userId, $startTime, $endTime, $tenantId, $recordTime, $workTimeRecordIds, $updateTime)
    {
        $user = model(UserModel::class)->find($userId);
        // 获取钉钉打卡工时
        $workHourList = teamones_request('teamones-work-hour', 'dingtalk/get_user_work_times', [
            "user_id_list" => [$user['union_id']],
            "tenant_id" => $tenantId,
            "work_date_from" => date('Y-m-d H:i:s', $startTime),
            "work_date_to" => date('Y-m-d H:i:s', $endTime)
        ]);
        $workHour = $workHourList["data"][0]["work_every_day_min"][$startTime] ?? [];
        if (empty($workHour)) {
            throw new LogicException("not checked in the day", ErrorCode::NOT_CHECKED_IN_THE_DAY);
        }
        $workHour = $workHour * 60;
        // 当天记录工时
        $workTimeRecordList = model(WorkTimeRecordModel::class)->where(['user_id' => $userId, 'record_time' => $recordTime])->select();
        $workTimeList = [];
        foreach ($workTimeRecordList as $workTimeRecordListItem) {
            $currentTime = $workTimeRecordListItem['work_time'];
            if (in_array($workTimeRecordListItem['id'], $workTimeRecordIds)) {
                $currentTime = $updateTime;
            }
            $workTimeList[] = $currentTime;
        }
        $sumWorkTime = array_sum($workTimeList);
        $remainingTime = (decimal_data($workHour / (60 * 60), 2) - decimal_data($sumWorkTime / (60 * 60), 2)) * (60 * 60);
        if (empty($remainingTime) || $remainingTime <= 0) {
            return false;
        }
        return true;
    }
}


